package controllers

import (
	"fmt"
	"github.com/goravel/framework/contracts/http"
	"github.com/goravel/framework/facades"
	"github.com/goravel/framework/support/path"
	"github.com/spf13/cast"
	"goravel/app/models"
	Services "goravel/app/services"
	Ftp "goravel/packages/ftpclient"
	SFtp "goravel/packages/sftpclient"
	"goravel/packages/socket/servers"
	"os"
)

type FtpController struct {
	//Dependent services
	parseBatchService *Services.BatchService
}

func NewFtpController() *FtpController {
	return &FtpController{
		//Inject services

	}
}

func (r *FtpController) My(ctx http.Context) http.Response {
	//获取最新的user_id=当前登录用户id的ftp配置
	var ftpconfig models.Configuration
	var user models.User
	facades.Auth().User(ctx, &user) // 必须是指针
	if err := facades.Orm().Query().Where("user_id", user.ID).Where("active=?", 1).First(&ftpconfig); err != nil {
		return ctx.Response().Status(http.StatusBadRequest).Json(http.Json{
			"message": "未找到ftp配置",
		})
	}
	return ctx.Response().Success().Json(http.Json{
		"data": ftpconfig,
	})
}

// 历史连接
func (r *FtpController) History(ctx http.Context) http.Response {
	user := models.User{}
	facades.Auth().User(ctx, &user)
	var ftpconfigs []models.Configuration
	if err := facades.Orm().Query().Where("user_id", user.ID).Order("id desc").Find(&ftpconfigs); err != nil {
		return ctx.Response().Status(http.StatusBadRequest).Json(http.Json{
			"message": "未找到ftp配置",
		})
	}
	return ctx.Response().Success().Json(http.Json{
		"data": ftpconfigs,
	})
}

func (r *FtpController) DownloadAndParse(ctx http.Context) http.Response {
	port := ctx.Request().Input("port")
	hostname := ctx.Request().Input("host")
	username := ctx.Request().Input("username")
	password := ctx.Request().Input("password")
	server_name := ctx.Request().Input("server_name")
	type_name := ctx.Request().Input("type")
	if server_name == "GG_Host" {
		type_name = "sftp"
	} else {
		type_name = "ftp"
	}
	//1、先从configuration表中查询出configuration
	var configuration models.Configuration
	if err := facades.Orm().Query().Where("host", hostname).Where("server_name", server_name).
		Where("port", port).
		Where("username", username).
		Where("password", password).
		First(&configuration); err != nil {
		facades.Log().Info("下载失败:", hostname+":"+port, username, password)
		return ctx.Response().Status(http.StatusBadRequest).Json(http.Json{
			"message": "未找到ftp配置,请检查！",
		})
	}
	//2、获取当前登录用户
	var user models.User
	if errUser := facades.Auth().User(ctx, &user); errUser != nil {
		return ctx.Response().Status(http.StatusBadRequest).Json(http.Json{
			"message": "未找到当前登录用户",
		})
	}
	go func() {
		err, _ := func(user models.User, configuration models.Configuration, port string, hostname string, username string, password string, type_name string) (error, string) {
			//3、启动下载任务
			var nmsg = "D:notice"
			nclient_id := facades.Cache().GetString(fmt.Sprintf("user:%d", user.ID)) // 获取缓存
			servers.SendMessage2Client(nclient_id, cast.ToString(user.ID), 200, "连接中", &nmsg)
			err, s := r.downloadTask(user, configuration, port, hostname, username, password, type_name)

			if err != nil {
				return err, s
			}
			var dmsg = "D:done"
			client_id := facades.Cache().GetString(fmt.Sprintf("user:%d", user.ID)) // 获取缓存
			servers.SendMessage2Client(client_id, cast.ToString(user.ID), 200, "下载完成", &dmsg)
			//4、启动解析任务
			r.parseTask(configuration, user)
			var pmsg = "P:done"
			servers.SendMessage2Client(client_id, cast.ToString(user.ID), 200, "解析完成", &pmsg)
			return nil, ""
		}(user, configuration, port, hostname, username, password, type_name)
		if err != nil {
			dmsg := "D:error"
			client_id := facades.Cache().GetString(fmt.Sprintf("user:%d", user.ID)) // 获取缓存
			servers.SendMessage2Client(client_id, cast.ToString(user.ID), 200, "下载失败:"+err.Error(), &dmsg)
		}

	}()

	return ctx.Response().Success().Json(http.Json{
		"message": "任务已启动",
		"data": map[string]string{
			"status": "working",
		},
	})
}

// 测试连通性
func (r *FtpController) Test(ctx http.Context) http.Response {
	user := models.User{}
	facades.Auth().User(ctx, &user)
	port := ctx.Request().Input("port")
	hostname := ctx.Request().Input("host")
	username := ctx.Request().Input("username")
	password := ctx.Request().Input("password")
	server_name := ctx.Request().Input("server_name")
	var type_name string
	//判断是ftp还是sftp
	if server_name == "GG_Host" {
		type_name = "sftp"
	} else {
		type_name = "ftp"
	}
	if type_name == "sftp" {
		facades.Log().Info("sftp:", hostname+":"+port, username, password)
		client, err := SFtp.NewSftpClient(hostname+":"+port, username, password)
		if client != nil {
			defer client.Close()
		}

		if err != nil {
			facades.Log().Info("sftp连接失败:", hostname+":"+port, username, password)
			return ctx.Response().Status(http.StatusBadRequest).Json(http.Json{
				"message": "连接失败" + err.Error(),
				"data": map[string]int{
					"active": 0,
				},
			})
		}

		_, err1 := client.FindFile("/")

		if err1 != nil {
			return ctx.Response().Status(http.StatusBadRequest).Json(http.Json{
				"message": "未找到文件：" + err.Error(),
				"data": map[string]int{
					"active": 0,
				},
			})

		}

		return ctx.Response().Success().Json(http.Json{
			"message": "连接成功",
			"data": map[string]int{
				"active": 1,
			},
		})
	}
	if type_name == "ftp" {
		facades.Log().Info("ftp:", hostname+":"+port, username, password)
		client, err := Ftp.NewClient(hostname+":"+port, username, password)
		if client != nil {
			defer client.Close()
		}
		if err != nil {
			facades.Log().Info("ftp连接失败:", hostname+":"+port, username, password)

			return ctx.Response().Status(http.StatusBadRequest).Json(http.Json{
				"message": "连接失败" + err.Error(),
				"data": map[string]int{
					"active": 0,
				},
			})
		}

		_, err1 := client.FindFile("/")

		if err1 != nil {
			return ctx.Response().Status(http.StatusBadRequest).Json(http.Json{
				"message": "未找到文件：" + err.Error(),
				"data": map[string]int{
					"active": 0,
				},
			})
		}

		return ctx.Response().Success().Json(http.Json{
			"message": "连接成功",
			"data": map[string]int{
				"active": 1,
			},
		})
	}
	return nil
}

// 保存
func (r *FtpController) Store(ctx http.Context) http.Response {
	var user models.User
	facades.Auth().User(ctx, &user) // 必须是指针

	var configuration models.Configuration
	//绑定参数
	if err1 := ctx.Request().Bind(&configuration); err1 != nil {
		return ctx.Response().Status(http.StatusBadRequest).Json(http.Json{
			"message": "参数错误",
		})
	}
	//关联创建该配置
	configuration.UserID = user.ID
	configuration.Active = 1
	if configuration.ServerName == "GG_Host" {
		configuration.Type = "sftp"
	} else {
		configuration.Type = "ftp"
	}

	if err := facades.Orm().Query().Create(&configuration); err != nil {
		return ctx.Response().Status(http.StatusBadRequest).Json(http.Json{
			"message": "保存失败：" + err.Error(),
		})
	}
	return ctx.Response().Success().Json(http.Json{
		"message": "保存成功",
		"data":    configuration,
	})
}

// 更新
func (r *FtpController) Update(ctx http.Context) http.Response {
	id := ctx.Request().Input("ID")
	port := ctx.Request().Input("port")
	hostname := ctx.Request().Input("host")
	username := ctx.Request().Input("username")
	password := ctx.Request().Input("password")
	serverName := ctx.Request().Input("server_name")
	serverPort := ctx.Request().Input("server_port")
	type_name := ctx.Request().Input("type")
	if serverName == "GG_Host" {
		type_name = "sftp"
	} else {
		type_name = "ftp"
	}
	user := models.User{}
	facades.Auth().User(ctx, &user)
	//说明这里连接成功，需要更新active字段为1
	var configuration models.Configuration
	//该用户所有的ftp配置都设置为0
	facades.Orm().Query().Model(&configuration).Where("user_id", user.ID).Update("active", 0)
	ftpconfig := models.Configuration{
		ServerName: serverName,
		Host:       hostname,
		Port:       port,
		ServerPort: serverPort,
		Username:   username,
		Password:   password,
		Type:       type_name,
		Active:     1,
	}
	if _, err := facades.Orm().Query().Where("id", id).Update(&ftpconfig); err != nil {
		return ctx.Response().Status(http.StatusBadRequest).Json(http.Json{
			"message": "更新失败：" + err.Error(),
		})
	}
	return ctx.Response().Success().Json(http.Json{
		"message": "更新成功",
		"data":    ftpconfig,
	})
}

// 1)下载task
/**
port := ctx.Request().Input("port")
hostname := ctx.Request().Input("host")
username := ctx.Request().Input("username")
password := ctx.Request().Input("password")
type_name := ctx.Request().Input("type")
*/
func (r *FtpController) Notice(user models.User, message string) {
	var stage = "D:notice"
	nclient_id := facades.Cache().GetString(fmt.Sprintf("user:%d", user.ID)) // 获取缓存
	servers.SendMessage2Client(nclient_id, cast.ToString(user.ID), 200, message, &stage)
}
func (r *FtpController) downloadTask(user models.User, config models.Configuration, port string, hostname string, username string, password string, type_name string) (error, string) {

	if type_name == "ftp" {
		r.Notice(user, "FTP连接初始化中...")
		client, err := Ftp.NewClient(hostname+":"+port, username, password)
		if client != nil {
			defer client.Close()
		}
		if err != nil {
			facades.Log().Info("ftp->下载连接失败:", hostname+":"+port, username, password)
			r.Notice(user, "FTP连接初始化失败...")
			return err, err.Error()
		}
		storePath := path.Public(type_name + "/" + hostname + "/" + port + "/" + username)
		//文件夹：根据结构host/port/username创建文件夹
		r.Notice(user, "创建保存文件夹...")
		_, err_dir := client.MkdirIfNotExisted(storePath)
		if err_dir != nil {
			facades.Log().Info("ftp->创建文件夹失败:", storePath)
			r.Notice(user, "本地文件夹创建失败:")
			return err_dir, "ftp->创建文件夹失败"
		}

		r.Notice(user, "正在检索目标文件夹，请稍后...")
		pathList, _ := client.WalkDir("Logs", "")
		remotePath := ""
		if len(pathList) > 0 {
			remotePath = pathList[0]
		} else {
			r.Notice(user, "未找到文件目标文件夹，请检查...")
			return nil, "未找到文件"
		}
		files, err := client.FindFile(remotePath)
		for index, v := range files {
			//1、下载过，且完全一样，跳过
			//去重：查询其他相同，但是文件大小不同的记录，删除
			var downloadRecord models.DownloadRecord
			facades.Orm().Query().
				Where("user_id", user.ID).
				Where("configuration_id", config.ID).
				Where("file_size", v.Size).
				Where("file_name", v.Name).
				First(&downloadRecord)
			if downloadRecord.ID != 0 {
				//说明下载过，将状态更新为不需要下载
				facades.Orm().Query().Model(&downloadRecord).Update("is_need_download_and_parse", 0)
				r.Notice(user, fmt.Sprintf("第%d个下载完成，%s请稍后...\n|(%d:%d)", index+1, v.Name, index+1, len(files)))
				fmt.Printf("第%d个，%s下载完成\n", index, v.Name)
				continue
			} else {
				//没有文件，下载，并记录
				r.Notice(user, fmt.Sprintf("第%d个有差异，重新下载，%s请稍后...\n|(%d:%d)", index+1, v.Name, index+1, len(files)))
				os.Remove(storePath + "/" + v.Name)
				//再次下载
				client.SaveFile(remotePath+"/"+v.Name, storePath+"/"+v.Name)
				//msg := fmt.Sprintf("D:%d:%d:%s", index+1, len(files), v.Name)
				//client_id := facades.Cache().GetString(fmt.Sprintf("user:%d", user.ID)) // 获取缓存
				//servers.SendMessage2Client(client_id, cast.ToString(user.ID), 200, "D:working", &msg)
				//创建下载记录
				facades.Orm().Query().Create(&models.DownloadRecord{
					FileName:               v.Name,
					FilePath:               remotePath + "/" + v.Name,
					FileSize:               cast.ToUint64(v.Size),
					CurrentOrder:           index + 1,
					UserID:                 user.ID,
					ConfigurationID:        config.ID,
					IsNeedDownloadAndParse: 1,
				})
			}

		}
	} else {
		r.Notice(user, "SFTP连接初始化中...")
		sftp_client, err := SFtp.NewSftpClient(hostname+":"+port, username, password)
		if sftp_client != nil {
			defer sftp_client.Close()
		}

		if err != nil {
			facades.Log().Info("sftp->下载连接失败:", hostname+":"+port, username, password)
			r.Notice(user, "SFTP连接初始化失败...")
			return err, err.Error()
		}
		storePath := path.Public(type_name + "/" + hostname + "/" + port + "/" + username)
		//文件夹：根据结构host/port/username创建文件夹
		r.Notice(user, "创建保存文件夹...")
		_, err_dir := sftp_client.MkdirIfNotExisted(storePath)
		if err_dir != nil {
			r.Notice(user, "本地文件夹创建失败...")
			facades.Log().Info("sftp->创建文件夹失败:", storePath)
			return err_dir, err_dir.Error()
		}

		r.Notice(user, "正在检索目标文件夹，请稍后...")
		pathList, _ := sftp_client.WalkDir("Logs", "")
		remotePath := ""
		if len(pathList) > 0 {
			remotePath = pathList[0]
		} else {
			r.Notice(user, "未找到文件目标文件夹，请检查...")
			return nil, "未找到文件"
		}

		//获取远程文件列表
		files, err := sftp_client.FindFile(remotePath)
		r.Notice(user, "正在获取目标文件，请稍后...")
		for index, v := range files {
			//1、2种情况，1是所有信息都相同，不下载直接跳过，2是文件名相同，但是文件大小不同，删除原来的文件，重新下载
			//去重：查询其他相同，但是文件大小不同的记录，删除
			var downloadRecord models.DownloadRecord
			facades.Orm().Query().
				Where("user_id", user.ID).
				Where("configuration_id", config.ID).
				Where("file_size", v.Size()).
				Where("file_name", v.Name()).
				First(&downloadRecord)
			if downloadRecord.ID != 0 {

				//说明下载过，将状态更新为不需要下载
				facades.Orm().Query().Model(&downloadRecord).Update("is_need_download_and_parse", 0)
				//跳过
				r.Notice(user, fmt.Sprintf("第%d个下载完成，%s请稍后...\n|(%d:%d)", index+1, v.Name(), index+1, len(files)))
				continue
			} else {
				//该文件可能存在，可能不存在，去重：删除真实文件
				os.Remove(storePath + "/" + v.Name())
				r.Notice(user, fmt.Sprintf("第%d个有差异，重新下载，%s请稍后...\n|(%d:%d)", index+1, v.Name(), index+1, len(files)))
				//再次下载
				sftp_client.SaveFile(remotePath+"/"+v.Name(), storePath+"/"+v.Name())
				fmt.Printf("第%d个，%s下载完成\n", index, v.Name())
				//创建下载记录
				facades.Orm().Query().Create(&models.DownloadRecord{
					FileName:               v.Name(),
					FilePath:               remotePath + "/" + v.Name(),
					FileSize:               cast.ToUint64(v.Size()),
					CurrentOrder:           index + 1,
					UserID:                 user.ID,
					ConfigurationID:        config.ID,
					IsNeedDownloadAndParse: 1,
				})
			}

		}
	}
	return nil, ""
}

// 2)解析task
func (r *FtpController) parseTask(configuration models.Configuration, user models.User) {
	foldPath := r.getPath(configuration)
	facades.Log().Info("解析任务启动中(文件夹）...", foldPath)
	batchService := r.parseBatchService.NewBatchService()
	batchService.ParseActionAll(foldPath, configuration.ID)
}

// 返回文件夹路径和配置id
func (r *FtpController) getPath(configuration models.Configuration) string {
	foldPath := configuration.Type + "/" + configuration.Host + "/" + configuration.Port + "/" + configuration.Username + "/"
	return foldPath
}
